package vip.aster.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.aster.common.constant.CacheConstants;
import vip.aster.common.constant.enums.StatusEnum;
import vip.aster.common.constant.enums.SysConfigEnum;
import vip.aster.common.exception.BusinessException;
import vip.aster.common.utils.CacheUtils;
import vip.aster.common.utils.PageInfo;
import vip.aster.framework.i18n.MessageUtils;
import vip.aster.system.entity.SysConfig;
import vip.aster.system.mapper.SysConfigMapper;
import vip.aster.system.query.SysConfigQuery;
import vip.aster.system.service.SysConfigService;
import vip.aster.system.vo.SysConfigVO;
import vip.aster.tenant.constants.TenantConstants;
import vip.aster.tenant.utils.TenantUtils;

import java.util.List;

/**
 * <p>
 * 系统配置 服务实现类
 * </p>
 *
 * @author Aster
 * @since 2023-11-28 10:36
 */
@Service
@AllArgsConstructor
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements SysConfigService {
    private SysConfigMapper sysConfigMapper;

    /**
     * 项目启动时，初始化参数到缓存
     */
    @PostConstruct
    public void init() {
        loadingConfigCache();
    }

    @Override
    public String selectConfigByKey(String configKey) {
        String key = TenantUtils.isEnable() ? (TenantUtils.getTenantId() + ":" + configKey)
                : (TenantConstants.DEFAULT_TENANT_ID + ":" + configKey);
        // 先从缓存中查
        String value = CacheUtils.get(CacheConstants.SYS_CONFIG_KEY, key, String.class);
        if (StrUtil.isNotBlank(value)) {
            return value;
        }
        // 缓存没有查数据库
        LambdaQueryWrapper<SysConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysConfig::getConfigKey, configKey).eq(SysConfig::getStatus, StatusEnum.ENABLE.getValue());
        List<SysConfig> configList = this.list(queryWrapper);
        if (CollUtil.isNotEmpty(configList)) {
            if (configList.size() == 1) {
                return configList.get(0).getConfigValue();
            }
            if (TenantUtils.isEnable()) {
                String tenantId = TenantUtils.getTenantId();
                for (SysConfig config : configList) {
                    if (StrUtil.isNotBlank(tenantId) && tenantId.equals(config.getTenantId())) {
                        return config.getConfigValue();
                    }
                }
            }
            for (SysConfig config : configList) {
                if (TenantConstants.DEFAULT_TENANT_ID.equals(config.getTenantId()) || StrUtil.isBlank(config.getTenantId())) {
                    return config.getConfigValue();
                }
            }
        }
        return null;
    }

    @Override
    public boolean selectCaptchaOnOff() {
        String value = this.selectConfigByKey(SysConfigEnum.CAPTCHA.getValue());
        return "true".equalsIgnoreCase(value);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void deleteConfigByIds(List<String> configIds) {
        List<SysConfig> list = this.listByIds(configIds);

        this.removeBatchByIds(configIds);

        for (SysConfig config : list) {
            String tenantId = StrUtil.isNotBlank(config.getTenantId()) ? config.getTenantId() : TenantConstants.DEFAULT_TENANT_ID;
            String key = tenantId + ":" + config.getConfigKey();
            CacheUtils.deleteIfPresent(CacheConstants.SYS_CONFIG_KEY, key);
        }
    }

    @Override
    public void loadingConfigCache() {
        List<SysConfig> configsList = this.list();
        for (SysConfig config : configsList) {
            String tenantId = StrUtil.isNotBlank(config.getTenantId()) ? config.getTenantId() : TenantConstants.DEFAULT_TENANT_ID;
            String key = tenantId + ":" + config.getConfigKey();
            CacheUtils.set(CacheConstants.SYS_CONFIG_KEY, key, config.getConfigValue());
        }
    }

    @Override
    public void clearConfigCache() {
        CacheUtils.clear(CacheConstants.SYS_CONFIG_KEY);
    }

    @Override
    public void resetConfigCache() {
        this.loadingConfigCache();
    }

    @Override
    public boolean checkConfigKeyUnique(SysConfig config) {
        LambdaQueryWrapper<SysConfig> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysConfig::getConfigKey, config.getConfigKey());
        if (StrUtil.isNotBlank(config.getId())) {
            queryWrapper.ne(SysConfig::getId, config.getId());
        }
        if (TenantUtils.isEnable()) {
            queryWrapper.eq(SysConfig::getTenantId, TenantUtils.getTenantId());
        }
        List<SysConfig> list = this.list(queryWrapper);
        return CollUtil.isEmpty(list);
    }

    @Override
    public PageInfo<SysConfigVO> pageList(SysConfigQuery query) {
        Page<SysConfig> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<SysConfig> pageList = sysConfigMapper.selectPage(page, getWrapper(query));
        return new PageInfo<>(SysConfigVO.convertList(pageList.getRecords()), pageList.getTotal());
    }

    @Override
    public void saveConfig(SysConfigVO configVO) {
        SysConfig config = new SysConfig();
        BeanUtil.copyProperties(configVO, config, true);

        // 校验参数键名是否唯一
        boolean checked = this.checkConfigKeyUnique(config);
        if (!checked) {
            throw new BusinessException(MessageUtils.message("config.key.exists"));
        }
        if (StrUtil.isNotBlank(config.getId())) {
            sysConfigMapper.updateById(config);
        } else {
            sysConfigMapper.insert(config);
        }
        CacheUtils.set(CacheConstants.SYS_CONFIG_KEY, config.getConfigKey(), config.getConfigValue());
    }

    private LambdaQueryWrapper<SysConfig> getWrapper(SysConfigQuery query) {
        LambdaQueryWrapper<SysConfig> wrapper = Wrappers.lambdaQuery();

        wrapper.like(StrUtil.isNotBlank(query.getConfigKey()), SysConfig::getConfigKey, query.getConfigKey());
        wrapper.like(StrUtil.isNotBlank(query.getConfigName()), SysConfig::getConfigName, query.getConfigName());
        wrapper.eq(StrUtil.isNotBlank(query.getConfigType()), SysConfig::getConfigType, query.getConfigType());
        wrapper.orderByDesc(SysConfig::getCreateTime);

        return wrapper;
    }
}
